﻿using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace SXFramWork.Core
{
    /// <summary>
    /// 通用扩展
    /// </summary>
    public static class CommonExtension
    {
        #region  Object转换
        /// <summary>
        /// 转为 Int
        /// </summary>
        /// <param name="thisValue"></param>
        /// <param name="errorValue">转换失败后的默认值</param>
        /// <returns></returns>
        public static int To_Int(this object thisValue, int errorValue=0)
        {
            int reval;
            if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }
        /// <summary>
        /// 转为 Long
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static long To_Long(this object s)
        {
            if (s == null || s == DBNull.Value)
                return 0L;

            long.TryParse(s.ToString(), out long result);
            return result;
        }
        /// <summary>
        /// 转为 String
        /// </summary>
        /// <param name="thisValue"></param>
        /// <param name="errorValue"></param>
        /// <returns></returns>
        public static string To_String(this object thisValue, string errorValue="")
        {
            if (thisValue != null) return thisValue.ToString().Trim();
            return errorValue;
        }

        /// <summary>
        /// 转为 Double
        /// </summary>
        /// <param name="s"></param>
        /// <param name="digits">小数位数</param>
        /// <returns></returns>
        public static double To_Double(this object s, int? digits = null)
        {
            if (s == null || s == DBNull.Value)
                return 0d;

            double.TryParse(s.ToString(), out double result);

            if (digits == null)
                return result;

            return Math.Round(result, digits.Value);
        }
        /// <summary>
        /// 转为 Decimal
        /// </summary>
        /// <param name="s"></param>
        /// <param name="decimals">小数位数</param>
        /// <returns></returns>
        public static decimal To_Decimal(this object s, int? decimals = null)
        {
            if (s == null || s == DBNull.Value) return 0m;

            decimal.TryParse(s.ToString(), out decimal result);

            if (decimals == null)
                return result;

            return Math.Round(result, decimals.Value);
        }

        /// <summary>
        /// 转为 DateTime
        /// </summary>
        /// <param name="thisValue"></param>
        /// <param name="errorValue"></param>
        /// <returns></returns>
        public static DateTime To_DateTime(this object thisValue, string errorValue="1900-1-1")
        {
            DateTime reval;
            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue.To_DateTime();
        }

        /// <summary>
        /// 转为 Byte
        /// </summary>
        /// <param name="s">输入字符串</param>
        /// <returns></returns>
        public static byte To_Byte(this object s)
        {
            if (s == null || s == DBNull.Value)
                return 0;
            byte.TryParse(s.ToString(), out byte result);
            return result;
        }

        /// <summary>
        /// 转为 float
        /// </summary>
        /// <param name="s"></param>
        /// <param name="decimals">小数位数</param>
        /// <returns></returns>
        public static float To_Float(this object s, int? decimals = null)
        {
            if (s == null || s == DBNull.Value)
                return 0f;

            float.TryParse(s.ToString(), out float result);

            if (decimals == null)
                return result;

            return (float)Math.Round(result, decimals.Value);
        }
        /// <summary>
        /// 转为 Boolean
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool To_Bool(this object s)
        {
            if (s == null) return false;
            s = s.ToString().ToLower();
            if (s.Equals(1) || s.Equals("1") || s.Equals("true") || s.Equals("是") || s.Equals("yes"))
                return true;
            if (s.Equals(0) || s.Equals("0") || s.Equals("false") || s.Equals("否") || s.Equals("no"))
                return false;
            Boolean.TryParse(s.ToString(), out bool result);
            return result;
        }

        #endregion
        #region 字节转换
        /// <summary>
        /// 转换为 16进制
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="lowerCase">是否小写</param>
        /// <returns></returns>
        public static string To_Hex(this byte[] bytes, bool lowerCase = true)
        {
            if (bytes == null)
                return null;

            var result = new StringBuilder();
            var format = lowerCase ? "x2" : "X2";
            for (var i = 0; i < bytes.Length; i++)
            {
                result.Append(bytes[i].ToString(format));
            }

            return result.ToString();
        }

        /// <summary>
        /// 16进制转字节数组
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static byte[] HexToBytes(this string s)
        {
            if (s.IsNull())
                return null;
            var bytes = new byte[s.Length / 2];

            for (int x = 0; x < s.Length / 2; x++)
            {
                int i = (Convert.ToInt32(s.Substring(x * 2, 2), 16));
                bytes[x] = (byte)i;
            }

            return bytes;
        }
        /// <summary>
        /// 转换为 Base64
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToBase64(this byte[] bytes)
        {
            if (bytes == null)
                return null;
            return Convert.ToBase64String(bytes);
        }

        #endregion


        /// <summary>
        /// 利用反射来判断对象是否包含某个属性
        /// </summary>
        /// <param name="instance">object</param>
        /// <param name="propertyName">需要判断的属性</param>
        /// <returns>是否包含</returns>
        public static bool ContainProperty(this object instance, string propertyName)
        {
            if (instance != null && !string.IsNullOrEmpty(propertyName))
            {
                PropertyInfo _findedPropertyInfo = instance.GetType().GetProperty(propertyName);
                return (_findedPropertyInfo != null);
            }
            return false;
        }

        /// <summary>
        /// 根据属性名取值
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="key"></param>
        /// <param name="err"></param>
        /// <returns></returns>
        public static object GetValueByProperty(this object obj, string key, object err = null)
        {

            Type t = obj.GetType();//获得该类的Type
            Object result = new object();
            foreach (PropertyInfo pi in t.GetProperties())
            {
                if (key == pi.Name)
                {
                    result = pi.GetValue(obj, null);
                    break;
                }
            }
            return result == null ? err : result;
        }

        /// <summary>
        ///  DateTime时间格式转换为Unix时间戳格式
        /// </summary>
        /// <param name="objValue"></param>
        /// <param name="iDefault"></param>
        /// <param name="throwE"></param>
        /// <returns></returns>
        public static long To_UnixTime(this DateTime objValue, long iDefault = 0, bool throwE = false)
        {
            try
            {
                var time = (objValue.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
                return time;
            }
            catch (Exception error)
            {
                if (throwE) throw error;
                return iDefault;
            }
        }



        /// <summary>
        /// 功能: 将Unix时间戳转换为DateTime类型时间
        /// </summary>
        /// <param name="objValue">源对象</param>
        /// <param name="sDefault">默认值</param>
        /// <param name="throwE">是否抛出异常</param>
        /// <returns>如果错误,返回 '1900-1-1'的日期</returns>
        public static DateTime To_Unix_DateTime(this long unixTime, string sDefault = "1900-1-1", bool throwE = false)
        {
            try
            {
                if (unixTime > 0)
                {
                    DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
                    return startTime.AddSeconds(unixTime);
                }
                else
                    return Convert.ToDateTime(sDefault);
            }
            catch (Exception error)
            {
                if (throwE) throw error;
                return Convert.ToDateTime(sDefault);
            }
        }
        /// <summary>
        /// 将对象转为json
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="dateFormat"></param>
        /// <returns></returns>
        public static string ToJson(this object obj)
        {
            return obj == null ? string.Empty : JsonConvert.SerializeObject(obj);
        }
    }
}
